#!/usr/bin/python
import simplejson, MuConnection, time
from StringIO import StringIO

"""
My rough scale notes to be replaced with better comments later

JSON objects
{
"musl":"scenario(name: \"http_get\") {}",
"csv":"",
"hosts":{"host_0":"b1/8.1.1.1","host_1":"b2/8.1.1.2"},
"delay":0,
"pattern":{"iterations":1,"intervals":[{"iterations":1,"end":100000,"start":5000,"duration":60}]}
}
"""

class MuScaleApi():

	VERBOSE = False
   	muConnection = None
   	json = None

	def __init__(self,connection):
		""" set up the TestAPI with the passed in MuConnection """
		self.muConnection = connection
		
		
	def newSession(self):
		""" start a new session 
			HTTP POST  https://MyMu/api/v5/scale/new/
		"""
		url = self.muConnection.TOP_LEVEL_URL + "/api/v5/scale/new/"
		responseData = self.muConnection.post(url, None, "text/xml", True)
		self.session = responseData
		if responseData.isCompleted() and not responseData.hasError():
			if responseData.getRawResponse() == '':
				responseData.setUUID('')
				responseData.setMessage('No UUID Found. No player available.')
				responseData.setCompleted(False)
				responseData.setError(True)
			else:
				responseData.setUUID(responseData.getRawResponse())
		if self.VERBOSE:
			print responseData
			print "newSession"
		return responseData
		
	def listActiveScalePlayers(self):
		""" List active players
			HTTP GET  https://MyMu/api/v5/scale/list
		"""
		url = self.muConnection.TOP_LEVEL_URL + '/api/v5/scale/list'
		responseData = self.muConnection.get(url)
		self.session = responseData
		if responseData.isCompleted() and not responseData.hasError():
			tmpS = responseData.getRawResponse().split('"')
			if len(tmpS)==3:
				responseData.setUUID(tmpS[1])
			else:
				responseData.setUUID('')
				responseData.setMessage('No UUID Found')
		if self.VERBOSE:
			print responseData
			print "listActiveScalePlayers"
		return responseData
		
	def initScalePlayer(self,scaleConfig,player_uuid):
		""" set up test and verrify: JSON object
			HTTP POST  https://MyMu/api/v5/scale/verify
			Should return a success
		"""
		#file = open('scale_params.json', 'r')
		#scaleJsonData = file.read()
		scaleJsonData = str(scaleConfig)
		self.json = scaleJsonData
		#scaleJsonData = scaleConfig.getScaleJsonConfig()
		url = self.muConnection.TOP_LEVEL_URL + '/api/v5/scale/verify'
		req = self.muConnection.getRequest('POST',url, scaleJsonData)
		req.get_method = lambda: 'POST'
		req.add_header('Content-Type', "text/xml; charset=UTF-8")
		req.add_header("User-Agent", self.muConnection.USERNAME)
		req.add_header("Keep-Alive", 115)
		req.add_header("Cookie", "uuid="+player_uuid)
		responseData = self.muConnection.executeRequest(req,True)
		responseData.setRequest(req)
		responseData.setUrl(url)
		if responseData.isCompleted() and not responseData.hasError():
			if responseData.getRetrievedObjectType()==responseData.SCALE_STATS:
				status = Status(responseData.getRetrievedObject())
				responseData.setRetrievedObject(status)
			else:
				if self.VERBOSE:
					print 'NO STATS FOUND during scale player init'
				responseData.setMessage('NO STATS FOUND')
				responseData.setCompleted(False)
				responseData.setError(True)
		self.session = responseData
		if self.VERBOSE:
			print responseData
			print "inintScalePlayer"
		return responseData
	
	
	def startScalePlayer(self,scaleConfig,player_uuid):
		""" Then kick it off with start
			HTTP POST  https://MyMu/api/v5/scale/start
			(mime-type = application/json, post content = params)
		"""
		url = self.muConnection.TOP_LEVEL_URL + '/api/v5/scale/start?uuid='+player_uuid
		
		scaleConfig = self.json
		
		req = self.muConnection.getRequest('POST',url,scaleConfig)
		req.get_method = lambda: 'POST'
		req.add_header('Content-Type', "application/json; charset=utf-8")
		req.add_header("User-Agent", self.muConnection.USERNAME)
		req.add_header("Keep-Alive", 115)
		req.add_header("Cookie", "uuid="+player_uuid)
		responseData = self.muConnection.executeRequest(req,True)
		if responseData.getRawResponse()=="{}":
			responseData.set
		self.session = responseData
		if self.VERBOSE:
			print responseData
			print "startScalePlayer"
		return responseData
		
	def getScalePlayerStatus(self, uuid):
		""" Monitor status
			HTTP GET  https://MyMu/api/v5/scale/status?uuid=<session_uuid>
			returns detaild json object
		"""
		url = self.muConnection.TOP_LEVEL_URL + '/api/v5/scale/status?uuid=' + uuid
		responseData = self.muConnection.get(url,True)
		self.session = responseData
		if responseData.isCompleted() and not responseData.hasError():
			if responseData.getRetrievedObjectType()==responseData.SCALE_STATS:
				status = Status(responseData.getRetrievedObject())
				responseData.setRetrievedObject(status)
			else:
				responseData.setMessage('NO STATS FOUND')
				responseData.setCompleted(False)
				responseData.setError(True)
		if self.VERBOSE:
			print responseData
			print "getScalePlayerStaus"
		return responseData
		
		
	def stopScalePlayer(self,player_uuid):
		""" Manualy stop test
			HTTP GET  https://MyMu/api/v5/scale/stop
		"""
		url = self.muConnection.TOP_LEVEL_URL + '/api/v5/scale/stop'
		req = self.muConnection.getRequest('GET',url,None)
		req.add_header('Content-Type', "application/json; charset=utf-8")
		req.add_header("User-Agent", self.muConnection.USERNAME)
		req.add_header("Keep-Alive", 115)
		req.add_header("Cookie", "uuid="+player_uuid)
		responseData = self.muConnection.executeRequest(req,True)
		self.session = responseData
		if self.VERBOSE:
			print responseData
			print "stopScalePlayer"
		return responseData
		
		
	def updateScalePatern(self,player_uuid,volume=None,delay=None):
		"""	Dynamic custom patern.  SWEET!!!!!!
			Can only be used if no paterns are set in initScalePlayer!!!!
			HTTP GET  https://MyMu/api/v5/scale/update/?volume=<new_volume>
			HTTP GET  https://MyMu/api/v5/scale/update/?delay=<new_delay> Does delay work????
		"""
		url = self.muConnection.TOP_LEVEL_URL + '/api/v5/scale/update?'
		if not volume==None:
			url = url + 'volume='+str(volume)
		if not delay==None:
			if not volume==None:
				url = url + '&'
			url = url + 'delay='+str(delay)
		req = self.muConnection.getRequest('GET',url,None)
		req.add_header('Content-Type', "application/json; charset=utf-8")
		req.add_header("User-Agent", self.muConnection.USERNAME)
		req.add_header("Keep-Alive", 115)
		req.add_header("Cookie", "uuid="+player_uuid)
		responseData = self.muConnection.executeRequest(req,True)
		self.session = responseData
		if self.VERBOSE:
			print responseData
			print "updateScalePatern"
		return responseData
		

	def releaseScalePlayer(self, uuid):
		""" To release the Scale Player (so another user can access it) use the /release method:
			HTTP GET https://MyMu/api/v5/scale/release?uuid=<session_uuid>
		"""
		url = self.muConnection.TOP_LEVEL_URL + '/api/v5/scale/release?uuid=' + uuid
		responseData = self.muConnection.get(url)
		#responseData = self.muConnection.get(url, None, None,True)
		self.session = responseData
		if self.VERBOSE:
			print responseData
			print "releaseScalePlayer"
		return responseData
		

class scaleConfig():

	scenarioMusl = None
	delay = 0
	pattern = {}
	csv = ''
	hosts = {}
	scaleJsonConfig = {'musl':scenarioMusl,'csv':csv,'hosts':hosts,'pattern':pattern,'delay':delay}
	
	#def __init__(self):
		
	def __str__(self):
		if self.pattern==None or self.pattern=={} or self.pattern=='':
			self.scaleJsonConfig = {'musl':self.scenarioMusl,'csv':self.csv,'hosts':self.hosts}
		else:
			self.scaleJsonConfig = {'musl':self.scenarioMusl,'csv':self.csv,'hosts':self.hosts,'pattern':self.pattern,'delay':self.delay}
		return simplejson.dumps(self.scaleJsonConfig)
	
	def loadScenarioMusl(self):
		print "TODO loadScenarioMusl"
		# need to get the roles and load the hosts as empty
	
	def setScenarioMusl(self, muslData):
		self.scenarioMusl = muslData
		
	def setCsv(self, csvData):
		self.csv = csvData

	def getHostsRoles(self):
		print "TODO eventualy used to get hostRoles to iterate through and set"
	
	def setHosts(self, hostRoleList):
		self.hosts = hostRoleList
		
	def setHostRole(self):
		print "TODO used to set or change the interface and inital ip of the host role"
		
	def setPattern(self,patternList):
		if patternList==None or patternList=={} or patternList=='':
			self.pattern = ''
		else:
			self.pattern = patternList
			self.volume = None
	
	def setDelay(self, delay):
		self.delay = delay

	
	def getScaleJsonConfig(self):
		if self.pattern==None or self.pattern=={} or self.pattern=='':
			self.scaleJsonConfig = {'musl':self.scenarioMusl,'csv':self.csv,'hosts':self.hosts}
		else:
			self.scaleJsonConfig = {'musl':self.scenarioMusl,'csv':self.csv,'hosts':self.hosts,'pattern':self.pattern,'delay':self.delay}
		return self.scaleJsonConfig
		

class Host():

	hostRole = None
	ip = None
	interface = None

class Patern():
	'''
		TODO: NEED TO CREATE PATERN MANAGMENT
		{"iterations":1,"intervals":[{"iterations":1,"end":100,"start":1,"duration":60}]}
	'''
	# EXAMPLE PATERNS
	TRIANGLE = {'pattern':{'iterations':4,'intervals': [ { "iterations" : 1, "duration" : 60, "start" : 100, "end" : 1000 }, { "iterations" : 1, "duration" : 60, "start" : 1000, "end" : 100}]}}
	SAW_TOOTH = {'pattern':{"iterations":4,"intervals": [{ "iterations" : 4, "duration" : 60, "start" : 100, "end" : 1000 }]}}
	SQUARE = {'pattern':{"iterations":4,"intervals": [{ "iterations" : 1, "duration" : 60, "start" : 100, "end" : 100 }, { "iterations" : 1, "duration" : 60, "start" : 1000, "end" : 1000}]}}
	RAMP_UP = {'pattern':{"iterations":1,"intervals": [{ "iterations" : 1, "duration" : 60, "start" : 100, "end" : 1000 }]}}
	RAMP_DOWN = {'pattern':{"iterations":1,"intervals": [{ "iterations" : 1, "duration" : 60, "start" : 1000, "end" : 100 }]}}
	CONSTANT = {'pattern':{"iterations":1,"intervals": [{ "iterations" : 1, "duration" : 60, "start" : 1000, "end" : 1000 }]}}
	STEP_UP = {'pattern':{"iterations":1,"intervals": [{ "iterations" : 1, "duration" : 60, "start" : 100, "end" : 100 },{ "iterations" : 1, "duration" : 60, "start" : 200, "end" : 200 },{ "iterations" : 1, "duration" : 60, "start" : 300, "end" : 300 },{ "iterations" : 1, "duration" : 60, "start" : 400, "end" : 400 },{ "iterations" : 1, "duration" : 60, "start" : 500, "end" : 500 },{ "iterations" : 1, "duration" : 60, "start" : 600, "end" : 600 },{ "iterations" : 1, "duration" : 60, "start" : 700, "end" : 700 },{ "iterations" : 1, "duration" : 60, "start" : 800, "end" : 800 },{ "iterations" : 1, "duration" : 60, "start" : 900, "end" : 900 },{ "iterations" : 1, "duration" : 60, "start" : 1000, "end" : 1000 }]}}
	
class Status():

	jsonData = {'statistics': {},'uuid': '', 'pollIndex': 0, 'running': False, 'systime': 0, '_id': '','okay': False}
	running = False
	uuid = None
	pollIndex = None
	systime = None
	_id = None
	okay = False
	statistics = None
	volume = 0
	
	def __init__(self,jsonData=None):
		if jsonData==None:
			return
		for key in jsonData:
			if key=='statistics':
				self.statistics = Statistics(jsonData[key])
				self.volume = self.statistics.volume
			elif key=='running':
				self.running = jsonData[key]
			elif key=='uuid':
				self.uuid = jsonData[key]
			elif key=='pollIndex':
				self.pollIndex = jsonData[key]
			elif key=='systime':
				self.systime = jsonData[key]
			elif key=='_id':
				self._id = jsonData[key]
			elif key=='okay':
				self.okay = jsonData[key]
			else:
				print "UKNOWN STATUS KEY IN MU SCALE API------> " + str(key)
				
	def __str__(self):
		return '{ running:'+str(self.running)+', okay:'+str(self.okay)+', pollIndex:'+str(self.pollIndex)+', volume:'+str(self.volume)+', uuid:'+str(self.uuid)+', systime:'+str(self.systime)+', _id:'+str(self._id)+', statistics:'+str(self.statistics)+'}'

class Statistics():
	"""	
		{'scenarios': [{'volume': 36, 'tests': [{'index': 0, 'server': {'rx': {'bytes': 11885276.0, 'msgs': 95849}, 'tx': {'bytes': 30671680.0, 'msgs': 95849}}, 'instances': {'executed': 95834, 'timeouts': 0, 'total': 95870, 'errors': 0}, 'client': {'rx': {'bytes': 30666880.0, 'msgs': 95834}, 'tx': {'bytes': 11886144.0, 'msgs': 95856}}, 'steps': [{'timeouts': 0, 'duration': {'max': 0.003764, 'avg': 0.0024740000000000001, 'min': 0.003264}, 'skipped': 0, 'executed': 95856, 'errors': 0}, {'timeouts': 0, 'duration': {'max': 0.0, 'avg': 0.0, 'min': 0.0}, 'skipped': 0, 'executed': 95856, 'errors': 0}, {'timeouts': 0, 'duration': {'max': 0.0020040000000000001, 'avg': 0.001041, 'min': 0.0}, 'skipped': 0, 'executed': 95849, 'errors': 0}, {'timeouts': 0, 'duration': {'max': 0.0, 'avg': 0.0, 'min': 0.0}, 'skipped': 0, 'executed': 95849, 'errors': 0}, {'timeouts': 0, 'duration': {'max': 0.001874, 'avg': 0.0010300000000000001, 'min': 0.0}, 'skipped': 0, 'executed': 95834, 'errors': 0}], 'asserts': [], 'duration': {'max': 0.013592, 'avg': 0.0042579999999999996, 'min': 0.0033960000000000001}}], 'hosts': [{'rtx': {'rx': {'bytes': 30666880.0, 'msgs': 95834}, 'tx': {'bytes': 11886144.0, 'msgs': 95856}}}, {'rtx': {'rx': {'bytes': 11885276.0, 'msgs': 95849}, 'tx': {'bytes': 30671680.0, 'msgs': 95849}}}], 'name': 0}], 'summary': {'duration': 17.796984999999999, 'instances': {'executed': 95834, 'timeouts': 0, 'total': 95870, 'errors': 0}, 'client': {'rx': {'bytes': 30666880.0, 'msgs': 95834}, 'tx': {'bytes': 11886144.0, 'msgs': 95856}}, 'asserts': {'failed': 0, 'executed': 0, 'errors': 0}, 'server': {'rx': {'bytes': 11885276.0, 'msgs': 95849}, 'tx': {'bytes': 30671680.0, 'msgs': 95849}}}}
	"""

	jsonData = None
	scenarios = []
	summary = None
	volume = 0
	def __init__(self, jsonData=None):
		if jsonData==None:
			return
		for key in jsonData:
			if key=='scenarios':
				self.scenarios = Scenarios(jsonData[key])
				self.volume = self.scenarios.volume
			if key=='summary':
				self.summary = Summary(jsonData[key])

		
	def __str__(self):
		return '{ scenarios:'+str(self.scenarios)+', summary:'+str(self.summary)+'}'
		
		
class Scenarios():
	
	scenarios = []
	
	# TODO: make volume a list
	volume = [0]
	
	
	def __init__(self, scenarioList=None):
		if scenarioList==None:
			return
		for jsonData in scenarioList:
			scenario = Scenario(jsonData)
			self.volume[0] = scenario.volume
	
	
class Scenario():

	# scenario keys
	VOLUME = 'volume'
	TESTS = 'tests'
	HOSTS = 'hosts'
	NAME = 'name'
	
	jsonData = None
	name = ''
	volume = 0
	hosts = []
	tests = []
	
	scenario = {VOLUME:'',TESTS:'',HOSTS:'',NAME:''}

	def __init__(self, jsonData=None):
		if jsonData==None:
			return
		for key in jsonData:
			if key==self.NAME:
				self.name = jsonData[key]
			if key==self.VOLUME:
				self.volume = jsonData[key]
			if key==self.HOSTS:
				self.hosts = jsonData[key]
				#print "-----> Key: "+key
				#for itum in jsonData[key]:
				#	hostStats = HostStats(itum)
			if key==self.TESTS:
				for itum in jsonData[key]:
					testStats = TestStats(itum)

		
	def __str__(self):
		self.jsonData = '{ scenarios:'+self.scenarios+',summary:'+self.summary+'}'
		return simplejson.dumps(self.jsonData)
		
class HostStats():
	"""
		TODO
	"""
	jsonData = None

	def __init__(self, jsonData=None):
		if jsonData==None:
			return
		for key in jsonData:
			print 'HostStats key --->' + key
			print str(jsonData[key])
		
		
class TestStats():

	jsonData = None
	INDEX = 'index'
	SERVER = 'server'
	INSTANCES = 'instances'
	CLIENT = 'client'
	STEPS = 'steps'
	ASERTS = 'asserts'
	DURATION = 'duration'
	
	index = 0
	server = None
	instances = None
	client = None
	asserts = None
	duration = None
	steps = []
	
	def __init__(self, jsonData=None):
		if jsonData==None:
			return
		for key in jsonData:
			if key==self.INDEX:
				self.index = jsonData[key]
			elif key==self.SERVER:
				self.server = jsonData[key]
			elif key==self.INSTANCES:
				self.instances = jsonData[key]
			elif key==self.CLIENT:
				self.client = jsonData[key]
			elif key==self.ASERTS:
				self.asserts = jsonData[key]
			elif key==self.DURATION:
				self.duration = jsonData[key]
			elif key==self.STEPS:
				self.steps = jsonData[key]
				#for itum in jsonData[key]:
				#	print responseData
				#	print "------- STEP -------"
				#	print itum
			else:
				print "UNKNOWN KEY IN TestStats"

		


class Summary():

	# -------- Json Keys
	DURATION = 'duration'
	INSTANCES = 'instances'
	CLIENT = 'client'
	SERVER = 'server'
	ASSERTS = 'asserts'
	
	jsonData = None
	
	jsonData = None
	duration = None
	instances = None
	client = None
	asserts = None
	server = None
	
	def __init__(self, jsonData=None):
		if jsonData==None:
			return
		for key in jsonData:
			if key==self.DURATION:
				self.duration = jsonData[self.DURATION]
			if key==self.INSTANCES:
				self.instances = jsonData[self.INSTANCES]
			if key==self.CLIENT:
				self.client = jsonData[self.CLIENT]
			if key==self.SERVER:
				self.server = jsonData[self.SERVER]
			if key==self.ASSERTS:
				self.asserts = jsonData[self.ASSERTS]
				
		
	def __str__(self):
		self.jsonData = {self.DURATION:self.duration,self.INSTANCES:self.instances,self.CLIENT:self.client,self.SERVER:self.server,self.ASSERTS:self.asserts}
		return simplejson.dumps(self.jsonData)